/***************************************************************************
* drv_l2_usbd_msdc_vendor.c
*
* Purpose: usb controller L2 msdc driver/interface for SCSI vendor command
*
* Author: Eugene Hsu
*
* Date: 2012/02/01
*
* Copyright Generalplus Corp. ALL RIGHTS RESERVED.
*
* Version : 
* History :
*
****************************************************************************/
/******************************************************
    Include file
******************************************************/
#include <string.h>
#include "drv_l1_rtc.h"
#include "drv_l1_usbd.h"
#include "drv_l2_usbd.h"
#include "drv_l2_usbd_msdc.h"
#include "drv_l2_usbd_msdc_vendor.h"

#define USBDL2MSDCVENDEG
#ifdef USBDL2MSDCVENDEG
#define USBD_L2MSDCVENLOG	print_string
#else
#define USBD_L2MSDCVENLOG(...)
#endif
extern USBD_MSDC_CTL_BLK	msdc_ctlblk;
extern USBD_MSDC_DMA_BUF	msdc_dma_buf[BOT_DMA_BUF_NUM];

extern void					scsi_send_stall_null(void);
extern void					scsi_command_fail(INT32U senseidx);
#if 0
extern						GoToRAMAddress(INT32U address);
#endif
extern INT32U				dmabufsize;

/******************************************************
    RTC Information
******************************************************/
#define RTC_RTCEN			(1 << 15)			/* RTC enable */
#define RTC_HMSEN			(1 << 9)			/* H/M/S function enable */

#define RTC_RETRY			1024

#define R_EXTRTC_CTRL		0x00
#define R_EXTRTC_LOAD_TIME0 0x10
#define R_EXTRTC_LOAD_TIME1 0x11
#define R_EXTRTC_LOAD_TIME2 0x12
#define R_EXTRTC_LOAD_TIME3 0x13
#define R_EXTRTC_LOAD_TIME4 0x14
#define R_EXTRTC_LOAD_TIME5 0x15

/******************************************************
    Variables declaration
******************************************************/
/* for SCSI vendor command usage, 20120626 */
char
	DeviceVersionInfo[] = { 0x10, //0~3: IC body
		0x00, 0x00, 0x01, 0xFF, //4~7: IC Version, 0xFFFFFF means mask rom
		0xFF, 0xFF, //
		0x03, 0x08, //Year
		0x01, //Month
		0x23, //Day
	};

USBD_MSDC_GP_VENDOR_CTL_BLK gp_vendor_ctl_blk = { drv_l2_usbd_msdc_gp_vendor_ram_read, drv_l2_usbd_msdc_gp_vendor_ram_write, NULL, GP_VENDER_NO_AUTH, 0, 0 };
extern INT8U				dmadone;

/******************************************************
    Utility functions
******************************************************/
/******************************************************
    State function declaration
    	
    	drv_l2_usbd_msdc_state_bot_vendor_in()
    	drv_l2_usbd_msdc_state_bot_vendor_out()
******************************************************/
#if 0
void drv_l2_usbd_msdc_state_bot_vendor_in(INT32U event)
{
	/* disable bulk in pkt */
	drv_l1_usbd_disable_bulk_in_out();
	switch(event)
	{
	case USBD_BULK_IN_ACK_EVENT:
		if(msdc_ctlblk.prostate == BULK_CSW_STA)
		{
			/* implement GoToRAMAddress function */
			GoToRAMAddress(gp_vendor_ctl_blk.scsi_vendor_lba);

			/* never back to here */
		}

		break;

	default:
		break;
	}
}

#endif
void drv_l2_usbd_msdc_state_bot_vendor_reg_write_out(INT32U event)
{
	INT8U	buf[4] = { 0 };

	drv_l1_usbd_disable_bulk_in_out();
	switch(event)
	{
	case USBD_BULK_OUT_READY_EVENT:
		if(msdc_ctlblk.prostate == BULK_DATA_STA)
		{
			/* for register write vendor command */
			drv_l1_usbd_rec_bulk_out((void *) buf, msdc_ctlblk.cbwdatatcnt);

			/* Write specified register */
			*((INT32U *) gp_vendor_ctl_blk.scsi_vendor_lba) = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];

			//DBG_PRINT("Vendor REG write, cnt = %d, val = 0x%x\r\n", msdc_ctlblk.cbwdatatcnt, (INT32U*)gp_vendor_ctl_blk.scsi_vendor_lba);
			//DBG_PRINT("Vendor REG write,reg 0x%x, data len %d\r\n", gp_vendor_ctl_blk.scsi_vendor_lba ,gp_vendor_ctl_blk.scsi_vendor_len);
			msdc_ctlblk.cbwdatatcnt = 0;
			msdc_ctlblk.csw.bCSWStatus = CSW_CMD_PASS_STA;
			msdc_ctlblk.cswdataresidue = 0;
			drv_l2_usbd_msdc_send_csw_data();	/* triggle next CBW */
		}

		break;

	default:
		break;
	}

	/* change back to normal MSDC state handler */
	drv_l2_usbd_register_state_handler(USBD_XFER_BULK, NULL, drv_l2_usbd_msdc_state_bot_in, drv_l2_usbd_msdc_state_bot_out);
}

/******************************************************
    API functions
******************************************************/
void drv_l2_usbd_msdc_register_vendor_read_write_fn(SCSI_VENDOR_READ_WRITE_FN read, SCSI_VENDOR_READ_WRITE_FN write)
{
	gp_vendor_ctl_blk.vnedor_read_fn = read;
	gp_vendor_ctl_blk.vnedor_write_fn = write;
}

INT32S drv_l2_usbd_msdc_gp_vendor_ram_write(INT32U addr, INT32U len, void *buf, void *pri)
{
	gp_memcpy((INT8S *) addr, (INT8S *) buf, (INT32U) len);
	return 0;
}

INT32S drv_l2_usbd_msdc_gp_vendor_ram_read(INT32U addr, INT32U len, void *buf, void *pri)
{
	gp_memcpy((INT8S *) buf, (INT8S *) addr, (INT32U) len);
	return 0;
}

void drv_l2_usbd_msdc_porcess_vendor_readwrite(void)
{
	INT32U	transfer_len;
	INT32S	ret = -1;

	if(msdc_ctlblk.doingSCSIreadwrite != DO_SCSI_VENDOR_READ && msdc_ctlblk.doingSCSIreadwrite != DO_SCSI_VENDOR_WRITE)
	{
		return;
	}

	/* Check BULK IN/OUT status */
	if(dmadone)
	{
		if(dmadone == DMA_BULK_IN_MODE)
		{
			if(msdc_ctlblk.dmaptr->DMABufState == SCSI_DMA_BUF_INING_STA)
			{
				//DBG_PRINT("BI done now, sta[%d][%d]\r\n", msdc_ctlblk.dmaptr->DMABufState,msdc_ctlblk.dmaptr->next->DMABufState);
				msdc_ctlblk.dmaptr->DMABufState = SCSI_DMA_BUF_IN_DONE_STA;
			}
		}
		else			// if(dmadone == DMA_BULK_OUT_MODE)
		{
			/* BULK OUT DMA */
			if(msdc_ctlblk.dmaptr->DMABufState == SCSI_DMA_BUF_OUTING_STA)
			{
				//DBG_PRINT("BO done now, sta[%d][%d]\r\n", msdc_ctlblk.dmaptr->DMABufState,msdc_ctlblk.dmaptr->next->DMABufState);
				msdc_ctlblk.dmaptr->DMABufState = SCSI_DMA_BUF_OUT_DONE_STA;
			}
			else
			if(msdc_ctlblk.dmaptr->next->DMABufState == SCSI_DMA_BUF_OUTING_STA)
			{
				//DBG_PRINT("BO done next, sta[%d][%d]\r\n", msdc_ctlblk.dmaptr->DMABufState,msdc_ctlblk.dmaptr->next->DMABufState);
				msdc_ctlblk.dmaptr->next->DMABufState = SCSI_DMA_BUF_OUT_DONE_STA;
			}
		}

		dmadone = 0;	/* reset dmadone flag */
	}

	if(msdc_ctlblk.dmaptr->DMABufState == SCSI_DMA_BUF_NOT_USED_STA)
	{
		if(msdc_ctlblk.doingSCSIreadwrite == DO_SCSI_VENDOR_WRITE)
		{
			/* Process vendor write */
			if(msdc_ctlblk.rambufcnt)
			{
				transfer_len = dmabufsize;
				msdc_ctlblk.dmaptr->DMABufState = SCSI_DMA_BUF_OUTING_STA;
				drv_l1_usbd_rec_bulk_out((void *) msdc_ctlblk.dmaptr->dataptr, transfer_len);
			}
			else
			if(msdc_ctlblk.rambufcnt == 0)
			{
				//DBG_PRINT("DO_SCSI_VENDOR_WRITE, enter CSW\r\n");
				/* reset the polling flag and state machine */
				msdc_ctlblk.doingSCSIreadwrite = DO_SCSI_NONE;
				msdc_dma_buf[0].DMABufState = SCSI_DMA_BUF_NOT_USED_STA;
				msdc_dma_buf[1].DMABufState = SCSI_DMA_BUF_NOT_USED_STA;

				/* Enter CBW state */
				msdc_ctlblk.cswdataresidue = 0;
				msdc_ctlblk.csw.bCSWStatus = CSW_CMD_PASS_STA;

				/* send CSW */
				drv_l2_usbd_msdc_send_csw_data();	/* triggle next CBW */
			}
		}
		else
		if(msdc_ctlblk.doingSCSIreadwrite == DO_SCSI_VENDOR_READ)
		{
			/* Process vendor read */
			if(msdc_ctlblk.rambufcnt == 0)
			{
				msdc_ctlblk.doingSCSIreadwrite = DO_SCSI_NONE;
				msdc_dma_buf[0].DMABufState = SCSI_DMA_BUF_NOT_USED_STA;
				msdc_dma_buf[1].DMABufState = SCSI_DMA_BUF_NOT_USED_STA;

				/* Enter CBW state */
				msdc_ctlblk.cswdataresidue = 0;
				msdc_ctlblk.csw.bCSWStatus = CSW_CMD_PASS_STA;

				//DBG_PRINT("Vendor read end!!\r\n");
				/* send CSW */
				drv_l2_usbd_msdc_send_csw_data();	/* triggle next CBW */
			}
			else						/* still have data to process */
			{
				ret = gp_vendor_ctl_blk.vnedor_read_fn((INT32U) gp_vendor_ctl_blk.vendordataptr, (INT32U) dmabufsize, (void *) msdc_ctlblk.dmaptr->dataptr, NULL);

				//DBG_PRINT("READ, addr 0x%x, dmaptr %p \r\n", gp_vendor_ctl_blk.vendordataptr,  msdc_ctlblk.dmaptr->dataptr);
				if(ret != 0)
				{
					/* return read failed*/
					msdc_ctlblk.doingSCSIreadwrite = DO_SCSI_NONE;
					scsi_send_stall_null();
					scsi_command_fail(0x04);
					return;
				}

				gp_vendor_ctl_blk.vendordataptr += dmabufsize;

				if(msdc_ctlblk.dmaptr->next->DMABufState == SCSI_DMA_BUF_NOT_USED_STA)
				{
					if((msdc_ctlblk.rambufcnt - 1) > 0)
					{
						/* copy data to next DMA buffer */
						ret = gp_vendor_ctl_blk.vnedor_read_fn((INT32U) gp_vendor_ctl_blk.vendordataptr, (INT32U) dmabufsize, (void *) msdc_ctlblk.dmaptr->next->dataptr, NULL);

						if(ret != 0)
						{
							/* return read failed*/
							msdc_ctlblk.doingSCSIreadwrite = DO_SCSI_NONE;
							scsi_send_stall_null();
							scsi_command_fail(0x04);
							return;
						}

						gp_vendor_ctl_blk.vendordataptr += dmabufsize;
						msdc_ctlblk.dmaptr->next->DMABufState = SCSI_DMA_BUF_READ_DONE_STA;
					}
				}

				msdc_ctlblk.dmaptr->DMABufState = SCSI_DMA_BUF_INING_STA;
				drv_l1_usbd_send_bulk_in((INT32U *) msdc_ctlblk.dmaptr->dataptr, dmabufsize);
			}
		}
	}
	else
	if(msdc_ctlblk.dmaptr->DMABufState == SCSI_DMA_BUF_IN_DONE_STA)
	{
		//DBG_PRINT("Vnedor read, SCSI_DMA_BUF_IN_DONE_STA\r\n");
		msdc_ctlblk.dmaptr->DMABufState = SCSI_DMA_BUF_NOT_USED_STA;
		msdc_ctlblk.dmaptr = msdc_ctlblk.dmaptr->next;

		if(msdc_ctlblk.rambufcnt)
		{
			msdc_ctlblk.rambufcnt--;
		}

		if(msdc_ctlblk.dmaptr->DMABufState == SCSI_DMA_BUF_READ_DONE_STA)
		{
			drv_l1_usbd_send_bulk_in((INT32U *) msdc_ctlblk.dmaptr->dataptr, dmabufsize);
			msdc_ctlblk.dmaptr->DMABufState = SCSI_DMA_BUF_INING_STA;
		}
	}
	else
	if(msdc_ctlblk.dmaptr->DMABufState == SCSI_DMA_BUF_OUT_DONE_STA)
	{
		/* Calculate DMA buffer */
		if(msdc_ctlblk.rambufcnt)
		{
			msdc_ctlblk.rambufcnt--;
		}

		/* Do next out DMA */
		if(msdc_ctlblk.dmaptr->next->DMABufState == SCSI_DMA_BUF_WRITE_DONE_STA || msdc_ctlblk.dmaptr->next->DMABufState == SCSI_DMA_BUF_NOT_USED_STA)
		{
			if(msdc_ctlblk.rambufcnt > 0)
			{
				transfer_len = dmabufsize;
				drv_l1_usbd_rec_bulk_out((void *) msdc_ctlblk.dmaptr->next->dataptr, transfer_len);
				msdc_ctlblk.dmaptr->next->DMABufState = SCSI_DMA_BUF_OUTING_STA;
			}
		}

		/* OUT DMA DONE, write into RAM, blocking action */
		ret = gp_vendor_ctl_blk.vnedor_write_fn((INT32U) gp_vendor_ctl_blk.vendordataptr, (INT32U) dmabufsize, (void *) msdc_ctlblk.dmaptr->dataptr, NULL);

		if(ret != 0)
		{
			/* write fault */
			msdc_ctlblk.doingSCSIreadwrite = DO_SCSI_NONE;
			scsi_send_stall_null();
			scsi_command_fail(0x02);	/* WRITE FAULT */
			return;
		}

		msdc_ctlblk.dmaptr->DMABufState = SCSI_DMA_BUF_WRITE_DONE_STA;
		gp_vendor_ctl_blk.vendordataptr += dmabufsize;
	}
	else
	if(msdc_ctlblk.dmaptr->DMABufState == SCSI_DMA_BUF_WRITE_DONE_STA)
	{
		//DBG_PRINT("DO_SCSI_VENDOR_WRITE, SCSI_DMA_BUF_WRITE_DONE_STA\r\n");
		msdc_ctlblk.dmaptr->DMABufState = SCSI_DMA_BUF_NOT_USED_STA;

		/* point to next DMA buffer */
		msdc_ctlblk.dmaptr = msdc_ctlblk.dmaptr->next;
	}
}

/**************************************************************
	SCSI vendor command functions to process GP's vendor command
**************************************************************/

/**************************************************************
    Funciton: gp_scsi_vendor_cmd_set_vendor_ID()    
**************************************************************/
void gp_scsi_vendor_cmd_set_vendor_ID(void)
{
	unsigned int	temp, i;
	INT8U			buf[4] = { 0 };

	temp = 0;

	for(i = 0; i < 7; i++)
	{
		temp += msdc_ctlblk.cbw.cbw_cb.CBWCB[2 + i];
	}

	temp ^= 0x4750;

	buf[0] = temp >> 8;
	buf[1] = temp;

	drv_l1_usbd_send_bulk_in((void *) buf, 2);
	msdc_ctlblk.cbwdatatcnt -= 2;
}

/**************************************************************
    Funciton: gp_scsi_vendor_cmd_get_driver_stauts()    
**************************************************************/
void gp_scsi_vendor_cmd_get_driver_stauts(void)
{
	INT8U	buf = 0;

	/* send lun number = 0 */
	drv_l1_usbd_send_bulk_in((void *) &buf, 1);
	msdc_ctlblk.cbwdatatcnt -= 1;
}

/**************************************************************
    Funciton: gp_scsi_vendor_cmd_get_driver_stauts()    
**************************************************************/
void gp_scsi_vendor_cmd_get_ic_version(void)
{
	drv_l1_usbd_send_bulk_in((void *) DeviceVersionInfo, 2);
	msdc_ctlblk.cbwdatatcnt -= 2;
}

/**************************************************************
    Funciton: gp_scsi_vendor_cmd_read()    
**************************************************************/
void gp_scsi_vendor_cmd_read(void)
{
	/* cbw_scsi_lba = start memory address, cbw_scsi_len = number of 512 bytes */
	drv_l2_usbd_msdc_get_read_lba_len(&gp_vendor_ctl_blk.scsi_vendor_lba, &gp_vendor_ctl_blk.scsi_vendor_len, 10);

	//DBG_PRINT("GP vendor cmd read, lba 0x%x, len %d\r\n",gp_vendor_ctl_blk.scsi_vendor_lba, gp_vendor_ctl_blk.scsi_vendor_len);
	/* Set DMA buffer's state */
	msdc_dma_buf[0].DMABufState = SCSI_DMA_BUF_NOT_USED_STA;
	msdc_dma_buf[1].DMABufState = SCSI_DMA_BUF_NOT_USED_STA;

	msdc_ctlblk.dmaptr = &msdc_dma_buf[0];
	msdc_ctlblk.rambufcnt = gp_vendor_ctl_blk.scsi_vendor_len;	//how many 512 bytes
	msdc_ctlblk.prostate = BULK_DATA_STA;
	msdc_ctlblk.doingSCSIreadwrite = DO_SCSI_VENDOR_READ;
	gp_vendor_ctl_blk.vendordataptr = (INT8U *) gp_vendor_ctl_blk.scsi_vendor_lba;

	//DBG_PRINT("GP vendor cmd read, rambufcnt %d, vendorptr %p\r\n", msdc_ctlblk.rambufcnt, gp_vendor_ctl_blk.vendordataptr);
}

/**************************************************************
    Funciton: gp_scsi_vendor_cmd_write()    
**************************************************************/
void gp_scsi_vendor_cmd_write(void)
{
	/* cbw_scsi_lba = start memory address, cbw_scsi_len = number of 512 bytes */
	drv_l2_usbd_msdc_get_read_lba_len(&gp_vendor_ctl_blk.scsi_vendor_lba, &gp_vendor_ctl_blk.scsi_vendor_len, 10);

	//DBG_PRINT("GP vendor cmd write, lba 0x%x, len %d\r\n",gp_vendor_ctl_blk.scsi_vendor_lba, gp_vendor_ctl_blk.scsi_vendor_len);
	/* Set DMA buffer's state */
	msdc_dma_buf[0].DMABufState = SCSI_DMA_BUF_NOT_USED_STA;
	msdc_dma_buf[1].DMABufState = SCSI_DMA_BUF_NOT_USED_STA;

	msdc_ctlblk.dmaptr = &msdc_dma_buf[0];
	msdc_ctlblk.rambufcnt = gp_vendor_ctl_blk.scsi_vendor_len;	//how many 512 bytes buufer
	msdc_ctlblk.prostate = BULK_DATA_STA;
	msdc_ctlblk.doingSCSIreadwrite = DO_SCSI_VENDOR_WRITE;
	gp_vendor_ctl_blk.vendordataptr = (INT8U *) gp_vendor_ctl_blk.scsi_vendor_lba;

	//DBG_PRINT("GP vendor cmd read, rambufcnt %d, vendorptr %p\r\n", msdc_ctlblk.rambufcnt, gp_vendor_ctl_blk.vendordataptr);
}

/**************************************************************
    Funciton: gp_scsi_vendor_cmd_goto_ram()    
**************************************************************/
#if 0
void gp_scsi_vendor_cmd_goto_ram(void)
{
	/* Enter CSW state */
	msdc_ctlblk.cbwdatatcnt = 0;
	msdc_ctlblk.csw.bCSWStatus = CSW_CMD_PASS_STA;
	msdc_ctlblk.cswdataresidue = 0;
	drv_l2_usbd_msdc_send_csw_data();	/* triggle next CBW */

	drv_l2_usbd_msdc_get_read_lba_len(&gp_vendor_ctl_blk.scsi_vendor_lba, &gp_vendor_ctl_blk.scsi_vendor_len, 10);

	/* Before jump to new RAM address, uninit all module in ROM code */
	//DBG_PRINT("gp_scsi_vendor_cmd_goto_ram, address 0x%x\r\n", gp_vendor_ctl_blk.scsi_vendor_lba);
	drv_l2_usbd_register_state_handler(USBD_XFER_BULK, NULL, drv_l2_usbd_msdc_state_bot_vendor_in, drv_l2_usbd_msdc_state_bot_out);
}

#endif

/**************************************************************
    Funciton: gp_scsi_vendor_cmd_reg_read()  
**************************************************************/
void gp_scsi_vendor_cmd_reg_read(void)
{
	/* lab is the address of specified register */
	drv_l2_usbd_msdc_get_read_lba_len(&gp_vendor_ctl_blk.scsi_vendor_lba, &gp_vendor_ctl_blk.scsi_vendor_len, 10);

#if 1
	gp_vendor_ctl_blk.scsi_vendor_len = ((*((INT32U *) gp_vendor_ctl_blk.scsi_vendor_lba) & 0xFF000000) >> 24) | ((*((INT32U *) gp_vendor_ctl_blk.scsi_vendor_lba) & 0x00FF0000) >> 8) | ((*((INT32U *) gp_vendor_ctl_blk.scsi_vendor_lba) & 0x0000FF00) << 8) | ((*((INT32U *) gp_vendor_ctl_blk.scsi_vendor_lba) & 0x000000FF) << 24);
#else
	gp_vendor_ctl_blk.scsi_vendor_len = *((INT32U *) gp_vendor_ctl_blk.scsi_vendor_lba);
#endif
	drv_l1_usbd_send_bulk_in((void *) &gp_vendor_ctl_blk.scsi_vendor_len, sizeof(gp_vendor_ctl_blk.scsi_vendor_len));

	//DBG_PRINT("gp_scsi_vendor_cmd_reg_read, reg 0x%x = 0x%x, len %d\r\n", gp_vendor_ctl_blk.scsi_vendor_lba, gp_vendor_ctl_blk.scsi_vendor_len, sizeof(gp_vendor_ctl_blk.scsi_vendor_len));
	/* Set CSW state */
	msdc_ctlblk.cbwdatatcnt -= sizeof(gp_vendor_ctl_blk.scsi_vendor_len);
	msdc_ctlblk.prostate = BULK_DATA_STA;	/* enter BOT DATA state */
	msdc_ctlblk.csw.bCSWStatus = CSW_CMD_PASS_STA;
	msdc_ctlblk.cswdataresidue = 0;
}

/**************************************************************
    Funciton: gp_scsi_vendor_cmd_reg_write()  
**************************************************************/
void gp_scsi_vendor_cmd_reg_write(void)
{
	/* lab is the address of specified register */
	drv_l2_usbd_msdc_get_read_lba_len(&gp_vendor_ctl_blk.scsi_vendor_lba, &gp_vendor_ctl_blk.scsi_vendor_len, 10);

	/* ebable bulk out */
	msdc_ctlblk.prostate = BULK_DATA_STA;	/* enter BOT DATA state */
	drv_l2_usbd_register_state_handler(USBD_XFER_BULK, NULL, drv_l2_usbd_msdc_state_bot_in, drv_l2_usbd_msdc_state_bot_vendor_reg_write_out);
	drv_l1_usbd_enable_rec_bulk_out_pkt();
}

/**************************************************************
    Funciton: gp_scsi_vendor_cmd_set_rtc()  
**************************************************************/
void gp_scsi_vendor_cmd_set_rtc(void)
{
	INT32U	rtc_ret;
	INT32U	gp_sec = (INT32U) (msdc_ctlblk.cbw.cbw_raw[24]);	// tm_sec;	/* 0-59 */
	INT32U	gp_min = (INT32U) (msdc_ctlblk.cbw.cbw_raw[23]);	// tm_min;	/* 0-59 */
	INT32U	gp_hour = (INT32U) (msdc_ctlblk.cbw.cbw_raw[22]);	// tm_hour; /* 0-23 */
	INT32U	gp_day = (INT32U) (msdc_ctlblk.cbw.cbw_raw[21]);	// tm_mday; /* 1-31 */

	//(INT32U)(msdc_ctlblk.cbw.cbw_raw[20]);	// tm_mon;	/* 1-12 */
	//(INT32U)(msdc_ctlblk.cbw.cbw_raw[18]<<8) | (msdc_ctlblk.cbw.cbw_raw[19]); // tm_year;
	INT64U	rtc_time = (gp_day * 60 * 60 * 24) + (gp_hour * 60 * 60) + (gp_min * 60) + gp_sec;
	rtc_time <<= 15;

	DBG_PRINT("date: %d_%d_%d_%d\r\n", gp_day, gp_hour, gp_min, gp_sec);
	{
		rtc_ret = ext_rtc_write(R_EXTRTC_LOAD_TIME2, (rtc_time >> 16) & 0xFF);
	}

	if(rtc_ret == 0)
	{
		rtc_ret = ext_rtc_write(R_EXTRTC_LOAD_TIME3, (rtc_time >> 24) & 0xFF);
	}

	if(rtc_ret == 0)
	{
		rtc_ret = ext_rtc_write(R_EXTRTC_LOAD_TIME4, (rtc_time >> 32) & 0xFF);
	}

	if(rtc_ret == 0)
	{
		rtc_ret = ext_rtc_write(R_EXTRTC_LOAD_TIME5, (rtc_time >> 40) & 0xFF);
	}

	DBG_PRINT("rtc_ret = %d\r\n", rtc_ret);
}

/***********************************************************************
*   void drv_l2_usbd_scsi_vendor_cmd(INT16U cmdval)                    *
*   opcode: 0xF0(240)~0xFF(255)                                        *
*   purpose: Implementation for SCSI vendor command                    * 
*                                                                      *
*                                                                      *  
***********************************************************************/
void drv_l2_usbd_scsi_vendor_cmd(INT16U cmdval)
{
	DBG_PRINT("Got vendor command 0x%x\r\n", cmdval);

	if(msdc_ctlblk.cbw.cbw_raw[29] != 'G' || msdc_ctlblk.cbw.cbw_raw[30] != 'P')
	{
		scsi_send_stall_null();
		scsi_command_fail(0x05);				//USB vendor command not have "GP" signature
		return;
	}

	/* GP standard authentication vendor command */
	/* First set CSW state */
	//msdc_ctlblk.cbwdatatcnt = 0;
	msdc_ctlblk.prostate = BULK_DATA_STA;		/* enter BOT DATA state */
	msdc_ctlblk.csw.bCSWStatus = CSW_CMD_PASS_STA;
	msdc_ctlblk.cswdataresidue = 0;

	/* In each case, exit this function if match following vendor command */
	switch(cmdval)
	{
#if 0

	case GP_READ_DRV_INFO:
		return;
#endif

	case GP_GET_IC_VER:
		/* Get IC version */
		gp_scsi_vendor_cmd_get_ic_version();
		return;

	case GP_GET_DRV_STATUS:
		/* Get LUN number */
		gp_scsi_vendor_cmd_get_driver_stauts();
		return;

	case 0xFFF0:
	case GP_SET_VENDOR_ID:
		/* Get vender ID for authentication*/
		gp_scsi_vendor_cmd_set_vendor_ID();

		//if(gp_vendor_ctl_blk.isauthrized == GP_VENDER_NO_AUTH)
		{
			gp_vendor_ctl_blk.isauthrized = GP_VENDER_START_AUTH;
		}

		return;

	case GP_SET_RTC_TIME:
		{
			ext_rtc_clock_enable();				/* enable ext rtc clock */
			ext_rtc_write(R_EXTRTC_CTRL, 0x15); // Up Count; RTC clk enable
			gp_scsi_vendor_cmd_set_rtc();

			/* CSW */
			msdc_ctlblk.cbwdatatcnt = 0;
			msdc_ctlblk.csw.bCSWStatus = CSW_CMD_PASS_STA;
			msdc_ctlblk.cswdataresidue = 0;
			drv_l2_usbd_msdc_send_csw_data();	/* triggle next CBW */
		}

		return;

	default:
		/* current command is not authenticaion command of GP's mass production tool */
		break;
	}

	/* Vendor read/write and control command */
	if(gp_vendor_ctl_blk.isauthrized == GP_VENDER_OK_AUTH)
	{
		switch(cmdval)
		{
		case GP_NV_READ:
			/* Read data from RAM */
			gp_scsi_vendor_cmd_read();
			break;

		case GP_NV_WRITE:
			/* Write bin file to internal RAM */
			gp_scsi_vendor_cmd_write();
			break;

		case GP_READ_MEMORY:
			/* Register read */
			gp_scsi_vendor_cmd_reg_read();
			break;

		case GP_WRITE_MEMORY:
			/* Register write */
			gp_scsi_vendor_cmd_reg_write();
			break;

		// This item just for rom code. Remark by josephhsieh@140319
		//case GP_USB_JUMP_CMD:
		/* Jump to RAM address specified by tool, and it never return back to this function!! */
		//gp_scsi_vendor_cmd_goto_ram();
		//break;
		default:
			/* An invalid vendor command occurred ,return fail */
			scsi_send_stall_null();
			scsi_command_fail(0x03);
			break;
		}
	}
	else
	{
		/* Finally, a none-authorized vendor command, return fail */
		scsi_send_stall_null();
		scsi_command_fail(0x03);
		return;
	}
}
